package com.jiang.books.domain;

import static javax.persistence.GenerationType.SEQUENCE;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.*;
import javax.validation.constraints.Size;

import org.hibernate.annotations.Type;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
import org.joda.time.DateTime;
import org.springframework.data.domain.Auditable;

/*
Create table jiang_author 
    (
		id                     Number(20,0) NOT NULL ENABLE,
		country_id             Number(20,0),
		first_name             Varchar2(100) NOT NULL ENABLE,
		last_name              Varchar2(100) NOT NULL ENABLE,
		first_name_native      Varchar2(100),
		last_name_native       Varchar2(100),
		photo                  BLOB,
		birth_date             Date,
		--died_date              Date NOT NULL ENABLE,
		description            Varchar2(1000),
		version                Number(10,0) DEFAULT 1 NOT NULL ENABLE,
		--audit
        created_by             Varchar2(20),
        created_date           TIMESTAMP,
        last_midified_by       Varchar2(20),
        last_modified_date     TIMESTAMP,
		CONSTRAINT pk_jiang_author PRIMARY KEY (id),
		CONSTRAINT fk_jiang_author FOREIGN KEY (country_id) REFERENCES jiang_country (id) ENABLE--,
		--CONSTRAINT uq_jiang_first_last_name UNIQUE (first_name, last_name)
	); 
*/

@Entity
@Audited
@Table(name = "jiang_author")
@NamedQueries({
	@NamedQuery(name="Author.findAll",
			    query="select a from Author a"),
	@NamedQuery(name="Author.findAllWithBooks",
                query="select distinct a from Author a left join fetch a.books b"),
    @NamedQuery(name="Author.findAllWithDetail",
                query="select distinct a from Author a left join fetch a.awards aw left join fetch a.books b"),
	@NamedQuery(name="Author.findById",
			    query="select distinct a from Author a left join fetch a.awards aw left join fetch a.books b where a.id = :id")
})
@SqlResultSetMapping(
		name="authorResult",
		entities=@EntityResult(entityClass=Author.class)
)
public class Author implements Auditable<String, BigInteger>, Serializable {

	private static final long serialVersionUID = 1L;
	
	private BigInteger id;
    private Country country;
	private String firstName;
	private String lastName;
	private String firstNameNative;
	private String lastNameNative;
	private byte[] photo;
	private Date birthDate;
    private String description;
    private int version;
    
	// Audit fields
	private String createdBy;
	private DateTime createdDate;	
	private String lastModifiedBy;
	private DateTime lastModifiedDate;

    private Set<Award> awards = new HashSet<Award>();
    private Set<Book> books = new HashSet<Book>();

    public Author() {
	}

	public Author(String firstName, String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}
	
	public Author(String firstName, String lastName, Country country) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.country = country;
	}

	public Author(String firstName, String lastName, Country country, Set<Book> books) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.country = country;
		this.books = books;
	}

	@Id
    @GeneratedValue(strategy = SEQUENCE, generator="JIANG_SEQ")
    @SequenceGenerator(name="JIANG_SEQ", sequenceName="jiang_id_sequence", allocationSize=300)
    @Column(name = "ID", unique = true, nullable = false)
	public BigInteger getId() {
		return this.id;
	}

	public void setId(BigInteger id) {
		this.id = id;
	}

    @ManyToOne
    @NotAudited
    @JoinColumn(name = "COUNTRY_ID")
    public Country getCountry() {
        return this.country;
    }

    public void setCountry(Country country) {
        this.country = country;
    }

	@Column(name = "FIRST_NAME", nullable = false)
	@Size(min=2, max=60)
	public String getFirstName() {
		return this.firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	@Column(name = "LAST_NAME", nullable = false)
	@Size(min=2, max=60)
	public String getLastName() {
		return this.lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	
	@Column(name = "FIRST_NAME_NATIVE")
	@Size(min=2, max=60)
	public String getFirstNameNative() {
		return this.firstNameNative;
	}

	public void setFirstNameNative(String firstNameNative) {
		this.firstNameNative = firstNameNative;
	}

	@Column(name = "LAST_NAME_NATIVE")
	@Size(min=2, max=60)
	public String getLastNameNative() {
		return this.lastNameNative;
	}

	public void setLastNameNative(String lastNameNative) {
		this.lastNameNative = lastNameNative;
	}
	
    @Lob
    @Column(name = "PHOTO")
    public byte[] getPhoto() {
        return photo;
    }

    public void setPhoto(byte[] photo) {
        this.photo = photo;
    }
	
	@Temporal(TemporalType.DATE)
	@Column(name = "BIRTH_DATE")
	public Date getBirthDate() {
		return this.birthDate;
	}

	public void setBirthDate(Date birthDate) {
		this.birthDate = birthDate;
	}
	
    @Column(name = "DESCRIPTION")
    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
    
    @Version
    @Column(name = "VERSION")
    public int getVersion() {
        return this.version;
    }

    public void setVersion(int version) {
        this.version = version;
    }


    @ManyToMany
    @NotAudited
    @JoinTable(name = "jiang_author_awards",
               joinColumns = @JoinColumn(name = "AUTHOR_ID"),
               inverseJoinColumns = @JoinColumn(name = "AWARD_ID"))
    public Set<Award> getAwards() {
        return this.awards;
    }

    public void setAwards(Set<Award> awards) {
        this.awards = awards;
    }

    @OneToMany(mappedBy = "author", cascade=CascadeType.ALL, orphanRemoval=true)
    public Set<Book> getBooks() {
        return this.books;
    }

    public void setBooks(Set<Book> books) {
        this.books = books;
    }

	public void addBook(Book book) {
		book.setAuthor(this);
		getBooks().add(book);
	}

	public void removeBook(Book book) {
		getBooks().remove(book);
	}
	
	
    // Audit methods
    @Column(name="CREATED_BY")
	public String getCreatedBy() {
		return createdBy;
	}

	public void setCreatedBy(String createdBy) {
		this.createdBy = createdBy;
	}

	@Column(name="CREATED_DATE")
	@Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")
	public DateTime getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(DateTime createdDate) {
		this.createdDate = createdDate;
	}

	@Column(name="LAST_MODIFIED_BY")
	public String getLastModifiedBy() {
		return lastModifiedBy;
	}
	
	public void setLastModifiedBy(String lastModifiedBy) {
		this.lastModifiedBy = lastModifiedBy;
	}

	@Column(name="LAST_MODIFIED_DATE")
	@Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")
	public DateTime getLastModifiedDate() {
		return lastModifiedDate;
	}

	public void setLastModifiedDate(DateTime lastModifiedDate) {
		this.lastModifiedDate = lastModifiedDate;
	}
    
	
	@Transient
	public boolean isNew() {
		if (id == null) {
			return true;
		} else {
			return false;
		}
	}

	public String toString() {
		return "Author - Id: " + getId() + ", First name: " + getFirstName()
				+ ", Last name: " + getLastName() + ", BirthDate: " + getBirthDate() + ", Country: " + getCountry();
	}
}